home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume26 / unproto / part02 < prev    next >
Encoding:
Text File  |  1991-12-07  |  21.7 KB  |  796 lines

  1. Newsgroups: comp.sources.misc
  2. From: wietse@wzv.win.tue.nl (Wietse Venema)
  3. Subject:  v26i095:  unproto - compile ANSI C with old C compiler, Part02/02
  4. Message-ID: <1991Dec1.143532.21763@sparky.imd.sterling.com>
  5. X-Md4-Signature: e41270a11de3ed19fd262a273924fc94
  6. Date: Sun, 1 Dec 1991 14:35:32 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: wietse@wzv.win.tue.nl (Wietse Venema)
  10. Posting-number: Volume 26, Issue 95
  11. Archive-name: unproto/part02
  12. Environment: SYSV2, SunOS
  13. Supersedes: unproto: Volume 23, Issue 12-13
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 2 (of 2)."
  22. # Contents:  unproto.c
  23. # Wrapped by wietse@wzv on Sun Dec  1 12:43:04 1991
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f unproto.c -a "${1}" != "-c" ; then 
  26.   echo shar: Will not over-write existing file \"unproto.c\"
  27. else
  28. echo shar: Extracting \"unproto.c\" \(19406 characters\)
  29. sed "s/^X//" >unproto.c <<'END_OF_unproto.c'
  30. X/*++
  31. X/* NAME
  32. X/*    unproto 1
  33. X/* SUMMARY
  34. X/*    ANSI C to old C converter
  35. X/* PACKAGE
  36. X/*    unproto
  37. X/* SYNOPSIS
  38. X/*    /lib/cpp ... | unproto
  39. X/*
  40. X/*    /somewhere/cpp ...
  41. X/* DESCRIPTION
  42. X/*    This document describes a filter that sits between the
  43. X/*    C preprocessor (usually \fI/lib/cpp\fP) and the next C compiler
  44. X/*    pass. It rewrites ANSI-C style function headers, function type
  45. X/*    declarations, function pointer types, and function pointer casts
  46. X/*    to old style. Other ANSI-isms are passed on without modification
  47. X/*    (token pasting, pragmas, etcetera).
  48. X/*
  49. X/*    For maximal flexibility, the "cpp | unproto" pipeline can  be
  50. X/*    packaged as an executable shell script named "/somewhere/cpp".
  51. X/*    This script should then be specified to the C compiler as a 
  52. X/*    non-default preprocessor. It will not work if your C compiler
  53. X/*    specifies output file names to the preprocessor.
  54. X/*
  55. X/*    The overhead of shell script interpretation can be avoided by
  56. X/*    having the unprototyper itself open the pipe to the preprocessor.
  57. X/*    In that case, the source should be compiled with the PIPE_THROUGH_CPP 
  58. X/*    macro defined (usually as "/lib/cpp"), and the resulting binary 
  59. X/*    should be installed as "/somewhere/cpp".
  60. X/* SEE ALSO
  61. X/* .ad
  62. X/* .fi
  63. X/*    cc(1), how to specify a non-default C preprocessor.
  64. X/*
  65. X/*    Some versions of the lint command are implemented as a shell
  66. X/*    script. It should require only minor modification for integration
  67. X/*    with the unprotoizer. Other versions of the lint command accept the same
  68. X/*    command syntax as the C compiler for the specification of a non-default
  69. X/*    preprocessor. Some research may be needed.
  70. X/* DIAGNOSTICS
  71. X/*    The progam will complain if it unexpectedly
  72. X/*    reaches the end of input.
  73. X/* BUGS
  74. X/*    Should be run on preprocessed source only, i.e. after macro expansion.
  75. X/*
  76. X/*    Declarations of (whatever) are misunderstood and will result in
  77. X/*    syntax errors.
  78. X/*
  79. X/*    Does not generate explicit type casts for function argument 
  80. X/*    expressions.
  81. X/* AUTHOR(S)
  82. X/*    Wietse Venema (wietse@wzv.win.tue.nl)
  83. X/*    Eindhoven University of Technology
  84. X/*    Department of Mathematics and Computer Science
  85. X/*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  86. X/* LAST MODIFICATION
  87. X/*    91/09/22 21:21:35
  88. X/* VERSION/RELEASE
  89. X/*    1.2
  90. X/*--*/
  91. X
  92. Xstatic char unproto_sccsid[] = "@(#) unproto.c 1.3 91/11/30 21:10:30";
  93. X
  94. X/* C library */
  95. X
  96. X#include <stdio.h>
  97. X#include <errno.h>
  98. X
  99. Xextern void exit();
  100. Xextern int optind;
  101. Xextern char *optarg;
  102. Xextern int getopt();
  103. X
  104. X/* Application-specific stuff */
  105. X
  106. X#include "vstring.h"
  107. X#include "stdarg.h"
  108. X#include "token.h"
  109. X#include "error.h"
  110. X#include "symbol.h"
  111. X
  112. X/* Forward declarations. */
  113. X
  114. Xstatic struct token *dcl_flush();
  115. Xstatic void block_flush();
  116. Xstatic void block_dcls();
  117. Xstatic struct token *show_func_ptr_type();
  118. Xstatic struct token *show_struct_type();
  119. Xstatic void show_arg_name();
  120. Xstatic void show_type();
  121. Xstatic void pair_flush();
  122. Xstatic void check_cast();
  123. X
  124. X#define    check_cast_flush(t)    (check_cast(t), tok_free(t))
  125. X
  126. X#ifdef PIPE_THROUGH_CPP
  127. Xstatic int pipe_stdin_through_cpp();
  128. X#endif
  129. X
  130. X/* Disable debugging printfs while preserving side effects. */
  131. X
  132. X#ifdef DEBUG
  133. X#define    DPRINTF    printf
  134. X#else
  135. X#define    DPRINTF (void)
  136. X#endif
  137. X
  138. X/* An attempt to make some complicated expressions a bit more readable. */
  139. X
  140. X#define    STREQ(x,y)        (*(x) == *(y) && !strcmp((x),(y)))
  141. X
  142. X#define    LAST_ARG_AND_EQUAL(s,c)    ((s)->next == 0 && (s)->head \
  143. X                && ((s)->head == (s)->tail) \
  144. X                && (STREQ((s)->head->vstr->str, (c))))
  145. X
  146. X#define    LIST_BEGINS_WITH_STAR(s) (s->head->head && s->head->head->tokno == '*')
  147. X
  148. X#define    IS_FUNC_PTR_TYPE(s)    (s->tokno == TOK_LIST && s->next \
  149. X                && s->next->tokno == TOK_LIST \
  150. X                && LIST_BEGINS_WITH_STAR(s))
  151. X
  152. X/* main - driver */
  153. X
  154. Xint     main(argc, argv)
  155. Xint     argc;
  156. Xchar  **argv;
  157. X{
  158. X    register struct token *t;
  159. X#ifdef    PIPE_THROUGH_CPP            /* pipe through /lib/cpp */
  160. X    int     cpp_status;
  161. X    int     wait_pid;
  162. X    int     cpp_pid;
  163. X
  164. X    cpp_pid = pipe_stdin_through_cpp(argv);
  165. X#endif
  166. X
  167. X    sym_init();                    /* prime the symbol table */
  168. X
  169. X    while (t = tok_class(DO_WSPACE)) {
  170. X    if (t = dcl_flush(t)) {            /* try declaration */
  171. X        if (t->tokno == '{') {        /* examine rejected token */
  172. X        block_flush(t);            /* body */
  173. X        } else {
  174. X        tok_flush(t);            /* other, recover */
  175. X        }
  176. X    }
  177. X    }
  178. X
  179. X#ifdef    PIPE_THROUGH_CPP            /* pipe through /lib/cpp */
  180. X    while ((wait_pid = wait(&cpp_status)) != -1 && wait_pid != cpp_pid)
  181. X     /* void */ ;
  182. X    return (wait_pid != cpp_pid || cpp_status != 0);
  183. X#else
  184. X    return (0);
  185. X#endif
  186. X}
  187. X
  188. X#ifdef    PIPE_THROUGH_CPP        /* pipe through /lib/cpp */
  189. X
  190. X/* pipe_stdin_through_cpp - avoid shell script overhead */
  191. X
  192. Xstatic int pipe_stdin_through_cpp(argv)
  193. Xchar  **argv;
  194. X{
  195. X    int     pipefds[2];
  196. X    int     pid;
  197. X    char  **cpptr = argv;
  198. X
  199. X    /*
  200. X     * With most UNIX implementations, the second non-option argument to
  201. X     * /lib/cpp specifies the output file. If an output file other than
  202. X     * stdout is specified, we must force /lib/cpp to write to stdout, and we
  203. X     * must redirect our own standard output to the specified output file.
  204. X     */
  205. X
  206. X#define    IS_OPTION(cp) ((cp)[0] == '-' && (cp)[1] != 0)
  207. X
  208. X    /* Skip to first non-option argument, if any. */
  209. X
  210. X    while (*++cpptr && IS_OPTION(*cpptr))
  211. X     /* void */ ;
  212. X
  213. X    /*
  214. X     * Assume that the first non-option argument is the input file name. The
  215. X     * next argument could be the output destination or an option (System V
  216. X     * Release 2 /lib/cpp gets the options *after* the file arguments).
  217. X     */
  218. X
  219. X    if (*cpptr && *++cpptr && **cpptr != '-') {
  220. X
  221. X    /*
  222. X     * The first non-option argument is followed by another argument that
  223. X     * is not an option ("-stuff") or a hyphen ("-"). Redirect our own
  224. X     * standard output before we clobber the file name.
  225. X     */
  226. X
  227. X    if (freopen(*cpptr, "w", stdout) == 0) {
  228. X        perror(*cpptr);
  229. X        exit(1);
  230. X    }
  231. X    /* Clobber the file name argument so that /lib/cpp writes to stdout */
  232. X
  233. X    *cpptr = "-";
  234. X    }
  235. X    /* Set up the pipe that connects /lib/cpp to our standard input. */
  236. X
  237. X    if (pipe(pipefds)) {
  238. X    perror("pipe");
  239. X    exit(1);
  240. X    }
  241. X    switch (pid = fork()) {
  242. X    case -1:                    /* error */
  243. X    perror("fork");
  244. X    exit(1);
  245. X    case 0:                    /* child */
  246. X    close(pipefds[0]);            /* close reading end */
  247. X    close(1);                /* connect stdout to pipe */
  248. X    if (dup(pipefds[1]) != 1)
  249. X        error(1, "dup() problem");
  250. X    close(pipefds[1]);            /* close redundant fd */
  251. X    execv(PIPE_THROUGH_CPP, argv);
  252. X    perror(PIPE_THROUGH_CPP);
  253. X    exit(1);
  254. X    default:                    /* parent */
  255. X    close(pipefds[1]);            /* close writing end */
  256. X    close(0);                /* connect stdin to pipe */
  257. X    if (dup(pipefds[0]) != 0)
  258. X        error(1, "dup() problem");
  259. X    close(pipefds[0]);            /* close redundant fd */
  260. X    return (pid);
  261. X    }
  262. X}
  263. X
  264. X#endif
  265. X
  266. X/* header_flush - rewrite new-style function header to old style */
  267. X
  268. Xstatic void header_flush(t)
  269. Xregister struct token *t;
  270. X{
  271. X    register struct token *s;
  272. X
  273. X    /* Do argument names, but suppress void and rewrite trailing ... */
  274. X
  275. X    if (LAST_ARG_AND_EQUAL(t->head, "void")) {
  276. X    put_str("()\n");            /* no arguments */
  277. X    } else {
  278. X    for (s = t->head; s; s = s->next) {    /* foreach argument... */
  279. X        if (LAST_ARG_AND_EQUAL(s, "...")) {
  280. X#ifdef _VA_ALIST_                /* see ./stdarg.h */
  281. X        put_ch(s->tokno);        /* ',' */
  282. X        put_str(_VA_ALIST_);        /* varargs magic */
  283. X#endif
  284. X        } else {
  285. X        put_ch(s->tokno);        /* opening '(' or ',' */
  286. X        show_arg_name(s);        /* extract argument name */
  287. X        }
  288. X    }
  289. X    put_str(")\n");                /* closing ')' */
  290. X    }
  291. X
  292. X    /* Do argument types, but suppress void and trailing ... */
  293. X
  294. X    if (!LAST_ARG_AND_EQUAL(t->head, "void")) {
  295. X    for (s = t->head; s; s = s->next) {    /* foreach argument... */
  296. X        if (!LAST_ARG_AND_EQUAL(s, "...")) {
  297. X        if (s->head != s->tail) {    /* really new-style argument? */
  298. X            show_line_control();    /* fix line number */
  299. X            show_type(s);        /* rewrite type info */
  300. X            put_str(";\n");
  301. X        }
  302. X        }
  303. X    }
  304. X    }
  305. X    tok_free(t);
  306. X    show_line_control();            /* because '{' follows */
  307. X}
  308. X
  309. X/* show_arg_name - extract argument name from argument type info */
  310. X
  311. Xstatic void show_arg_name(s)
  312. Xregister struct token *s;
  313. X{
  314. X    if (s->head) {
  315. X    register struct token *p;
  316. X    register struct token *t = 0;
  317. X
  318. X    /* Find the last interesting item. */
  319. X
  320. X    for (p = s->head; p; p = p->next) {
  321. X        if (p->tokno == TOK_WORD) {
  322. X        t = p;                /* remember last word */
  323. X        } else if (IS_FUNC_PTR_TYPE(p)) {
  324. X        t = p;                /* or function pointer */
  325. X        p = p->next;
  326. X        }
  327. X    }
  328. X
  329. X    /* Extract argument name from last interesting item. */
  330. X
  331. X    if (t) {
  332. X        if (t->tokno == TOK_LIST)
  333. X        show_arg_name(t->head);        /* function pointer, recurse */
  334. X        else
  335. X        tok_show(t);            /* print last word */
  336. X    }
  337. X    }
  338. X}
  339. X
  340. X/* show_type - rewrite type to old-style syntax */
  341. X
  342. Xstatic void show_type(s)
  343. Xregister struct token *s;
  344. X{
  345. X    register struct token *p;
  346. X
  347. X    for (p = s->head; p; p = p->next) {
  348. X    if (IS_FUNC_PTR_TYPE(p)) {
  349. X        p = show_func_ptr_type(p);        /* function pointer type */
  350. X    } else {
  351. X        tok_show(p);            /* other */
  352. X    }
  353. X    }
  354. X}
  355. X
  356. X/* show_func_ptr_type - display function_pointer type using old-style syntax */
  357. X
  358. Xstatic struct token *show_func_ptr_type(t)
  359. Xstruct token *t;
  360. X{
  361. X    register struct token *s;
  362. X
  363. X    /*
  364. X     * Rewrite (list1) (list2) to (list1) (). Only (list1) is given to us;
  365. X     * the caller must have verified the presence of (list2). Account for the
  366. X     * rare case that (list1) is a comma-separated list. That should be an
  367. X     * error, but we do not want to waste any information.
  368. X     */
  369. X
  370. X    for (s = t->head; s; s = s->next) {
  371. X    put_ch(s->tokno);            /* opening paren or ',' */
  372. X    show_type(s);                /* recurse */
  373. X    }
  374. X    put_str(")()");                /* closing paren */
  375. X    return (t->next);
  376. X}
  377. X
  378. X/* show_struct_type - display structured type, rewrite function-pointer types */
  379. X
  380. Xstatic struct token *show_struct_type(p)
  381. Xregister struct token *p;
  382. X{
  383. X    tok_show(p);                /* opening brace */
  384. X
  385. X    while (p->next) {                /* XXX cannot return 0 */
  386. X    p = p->next;
  387. X    if (IS_FUNC_PTR_TYPE(p)) {
  388. X        p = show_func_ptr_type(p);        /* function-pointer member */
  389. X    } else if (p->tokno == '{') {
  390. X        p = show_struct_type(p);        /* recurse */
  391. X    } else {
  392. X        tok_show(p);            /* other */
  393. X        if (p->tokno == '}') {
  394. X        return (p);            /* done */
  395. X        }
  396. X    }
  397. X    }
  398. X    DPRINTF("/* missing '}' */");
  399. X    return (p);
  400. X}
  401. X
  402. X/* is_func_ptr_cast - recognize function-pointer type cast */
  403. X
  404. Xstatic int is_func_ptr_cast(t)
  405. Xregister struct token *t;
  406. X{
  407. X    register struct token *p;
  408. X
  409. X    /*
  410. X     * Examine superficial structure. Require (list1) (list2). Require that
  411. X     * list1 begins with a star.
  412. X     */
  413. X
  414. X    if (!IS_FUNC_PTR_TYPE(t))
  415. X    return (0);
  416. X
  417. X    /*
  418. X     * Make sure that there is no name in (list1). Do not worry about
  419. X     * unexpected tokens, because the compiler will complain anyway.
  420. X     */
  421. X
  422. X    for (p = t->head->head; p; p = p->next) {
  423. X    switch (p->tokno) {
  424. X    case TOK_LIST:                /* recurse */
  425. X        return (is_func_ptr_cast(p));
  426. X    case TOK_WORD:                /* name in list */
  427. X        return (0);
  428. X    }
  429. X    }
  430. X    return (1);                    /* no name found */
  431. X}
  432. X
  433. X/* check_cast - display ()-delimited, comma-separated list */
  434. X
  435. Xstatic void check_cast(t)
  436. Xstruct token *t;
  437. X{
  438. X    register struct token *s;
  439. X    register struct token *p;
  440. X
  441. X    /*
  442. X     * Rewrite function-pointer types and function-pointer casts. Do not
  443. X     * blindly rewrite (*list1)(list2) to (*list1)(). Function argument lists
  444. X     * are about the only thing we can discard without provoking diagnostics
  445. X     * from the compiler.
  446. X     */
  447. X
  448. X    for (s = t->head; s; s = s->next) {
  449. X    put_ch(s->tokno);            /* opening paren or ',' */
  450. X    for (p = s->head; p; p = p->next) {
  451. X        switch (p->tokno) {
  452. X        case TOK_LIST:
  453. X        if (is_func_ptr_cast(p)) {    /* not: IS_FUNC_PTR_TYPE(p) */
  454. X            p = show_func_ptr_type(p);    /* or we might take away */
  455. X        } else {            /* function-call arguments */
  456. X            check_cast(p);        /* recurse */
  457. X        }
  458. X        break;
  459. X        case '{':
  460. X        p = show_struct_type(p);    /* rewrite func. ptr. types */
  461. X        break;
  462. X        default:
  463. X        tok_show(p);
  464. X        break;
  465. X        }
  466. X    }
  467. X    }
  468. X    put_ch(')');                /* closing paren */
  469. X}
  470. X
  471. X/* block_dcls - on the fly rewrite decls/initializers at start of block */
  472. X
  473. Xstatic void block_dcls()
  474. X{
  475. X    register struct token *t;
  476. X
  477. X    /*
  478. X     * Away from the top level, a declaration should be preceded by type or
  479. X     * storage-class information. That is why inside blocks, structs and
  480. X     * unions we insist on reading one word before passing the _next_ token
  481. X     * to the dcl_flush() function.
  482. X     * 
  483. X     * Struct and union declarations look the same everywhere: we make an
  484. X     * exception for these more regular constructs and pass the "struct" and
  485. X     * "union" tokens to the type_dcl() function.
  486. X     */
  487. X
  488. X    while (t = tok_class(DO_WSPACE)) {
  489. X    switch (t->tokno) {
  490. X    case TOK_WSPACE:            /* preserve white space */
  491. X    case '\n':                /* preserve line count */
  492. X        tok_flush(t);
  493. X        break;
  494. X    case TOK_WORD:                /* type declarations? */
  495. X        tok_flush(t);            /* advance to next token */
  496. X        t = tok_class(DO_WSPACE);        /* null return is ok */
  497. X    case TOK_COMPOSITE:            /* struct or union */
  498. X        if ((t = dcl_flush(t)) == 0)
  499. X        break;
  500. X        /* FALLTRHOUGH */
  501. X    default:                /* end of declarations */
  502. X        DPRINTF("/* end dcls */");
  503. X        /* FALLTRHOUGH */
  504. X    case '}':                /* end of block */
  505. X        tok_unget(t);
  506. X        return;
  507. X    }
  508. X    }
  509. X}
  510. X
  511. X/* block_flush - rewrite struct, union or statement block on the fly */
  512. X
  513. Xstatic void block_flush(t)
  514. Xregister struct token *t;
  515. X{
  516. X    static int count = 0;
  517. X
  518. X    tok_flush(t);
  519. X    DPRINTF("/*%d*/", ++count);
  520. X
  521. X    /*
  522. X     * Rewrite function pointer types in declarations and function pointer
  523. X     * casts in initializers at start of block.
  524. X     */
  525. X
  526. X    block_dcls();
  527. X
  528. X    /* Remainder of block: only rewrite function pointer casts. */
  529. X
  530. X    while (t = tok_class(DO_WSPACE)) {
  531. X    if (t->tokno == TOK_LIST) {
  532. X        check_cast_flush(t);
  533. X    } else if (t->tokno == '{') {
  534. X        block_flush(t);
  535. X    } else {
  536. X        tok_flush(t);
  537. X        if (t->tokno == '}') {
  538. X        DPRINTF("/*%d*/", count--);
  539. X        return;
  540. X        }
  541. X    }
  542. X    }
  543. X    DPRINTF("/* missing '}' */");
  544. X}
  545. X
  546. X/* pair_flush - on the fly rewrite casts in grouped stuff */
  547. X
  548. Xstatic void pair_flush(t, start, stop)
  549. Xregister struct token *t;
  550. Xregister int start;
  551. Xregister int stop;
  552. X{
  553. X    tok_flush(t);
  554. X
  555. X    while (t = tok_class(DO_WSPACE)) {
  556. X    if (t->tokno == start) {        /* recurse */
  557. X        pair_flush(t, start, stop);
  558. X    } else if (t->tokno == TOK_LIST) {    /* expression or cast */
  559. X        check_cast_flush(t);
  560. X    } else {                /* other, copy */
  561. X        tok_flush(t);
  562. X        if (t->tokno == stop) {        /* done */
  563. X        return;
  564. X        }
  565. X    }
  566. X    }
  567. X    DPRINTF("/* missing '%c' */", stop);
  568. X}
  569. X
  570. X/* initializer - on the fly rewrite casts in initializer */
  571. X
  572. Xstatic void initializer()
  573. X{
  574. X    register struct token *t;
  575. X
  576. X    while (t = tok_class(DO_WSPACE)) {
  577. X    switch (t->tokno) {
  578. X    case ',':                /* list separator */
  579. X    case ';':                /* list terminator */
  580. X        tok_unget(t);
  581. X        return;
  582. X    case TOK_LIST:                /* expression or cast */
  583. X        check_cast_flush(t);
  584. X        break;
  585. X    case '[':                /* array substript, may nest */
  586. X        pair_flush(t, '[', ']');
  587. X        break;
  588. X    case '{':                /* structured data, may nest */
  589. X        pair_flush(t, '{', '}');
  590. X        break;
  591. X    default:                /* other, just copy */
  592. X        tok_flush(t);
  593. X        break;
  594. X    }
  595. X    }
  596. X}
  597. X
  598. X/* func_ptr_dcl_flush - rewrite function pointer declaration */
  599. X
  600. Xstatic struct token *func_ptr_dcl_flush(list)
  601. Xregister struct token *list;
  602. X{
  603. X    register struct token *t;
  604. X
  605. X    /*
  606. X     * Ignore blanks because they would be output earlier than the list that
  607. X     * preceded them... Recover gracefully from syntax errors.
  608. X     */
  609. X
  610. X    while (t = tok_class(NO_WSPACE)) {
  611. X    switch (t->tokno) {
  612. X    case '\n':                /* preserve line count */
  613. X        tok_flush(t);
  614. X        break;
  615. X    case TOK_LIST:
  616. X        /* Function pointer type: (list1) (list2) -> (list1) () */
  617. X        (void) show_func_ptr_type(list);    /* may be recursive */
  618. X        tok_free(list);
  619. X        tok_free(t);
  620. X        return (0);
  621. X    default:                /* not a declaration */
  622. X        tok_unget(t);
  623. X        return (list);
  624. X    }
  625. X    }
  626. X
  627. X    /* Hit EOF; must be mistake, but do not waste any information. */
  628. X
  629. X    return (list);
  630. X}
  631. X
  632. X/* function_dcl_flush - rewrite function { heading, type declaration } */
  633. X
  634. Xstatic struct token *function_dcl_flush(list)
  635. Xregister struct token *list;
  636. X{
  637. X    register struct token *t;
  638. X
  639. X    /*
  640. X     * Ignore blanks because they would be output earlier than the list that
  641. X     * preceded them...
  642. X     */
  643. X
  644. X    while (t = tok_class(NO_WSPACE)) {
  645. X    switch (t->tokno) {
  646. X    case '\n':
  647. X        /* Preserve line count */
  648. X        tok_flush(t);
  649. X        break;
  650. X    case '{':
  651. X        /* Function heading: word (list) { -> old style heading */
  652. X        header_flush(list);
  653. X        tok_unget(t);
  654. X        return (0);
  655. X    case TOK_WORD:
  656. X        /* Old-style function heading: word (list) word...{ */
  657. X        tok_flush(list);
  658. X        tok_unget(t);
  659. X        return (0);
  660. X    case TOK_LIST:
  661. X        /* Function typedef? word (list1) (list) -> word (list1) () */
  662. X        tok_flush(list);
  663. X        put_str("()");
  664. X        tok_free(t);
  665. X        return (0);
  666. X    case ',':
  667. X    case ';':
  668. X        /* Function type declaration: word (list) -> word () */
  669. X        tok_free(list);
  670. X        put_str("()");
  671. X        tok_unget(t);
  672. X        return (0);
  673. X    default:
  674. X        /* Something else, reject the list. */
  675. X        tok_unget(t);
  676. X        return (list);
  677. X    }
  678. X    }
  679. X
  680. X    /* Hit EOF; must be mistake, but do not waste any information. */
  681. X
  682. X    return (list);
  683. X}
  684. X
  685. X/* dcl_flush - parse declaration on the fly, return rejected token */
  686. X
  687. Xstatic struct token *dcl_flush(t)
  688. Xregister struct token *t;
  689. X{
  690. X    register int got_word;
  691. X
  692. X    /*
  693. X     * Away from the top level, type or storage-class information is required
  694. X     * for an (extern or forward) function type declaration or a variable
  695. X     * declaration.
  696. X     * 
  697. X     * With our naive word-counting approach, this means that the caller should
  698. X     * read one word before passing the next token to us. This is how we
  699. X     * distinguish, for example, function declarations from function calls.
  700. X     * 
  701. X     * An exception are structs and unions, because they look the same at any
  702. X     * level. The caller should give is the "struct" or "union" token.
  703. X     */
  704. X
  705. X    for (got_word = 0; t; t = tok_class(DO_WSPACE)) {
  706. X    switch (t->tokno) {
  707. X    case TOK_WSPACE:            /* advance past blanks */
  708. X    case '\n':                /* advance past newline */
  709. X    case '*':                /* indirection: keep trying */
  710. X        tok_flush(t);
  711. X        break;
  712. X    case TOK_WORD:                /* word: keep trying */
  713. X    case TOK_COMPOSITE:            /* struct or union */
  714. X        got_word = 1;
  715. X        tok_flush(t);
  716. X        break;
  717. X    default:
  718. X
  719. X        /*
  720. X         * Function pointer types can be preceded by zero or more words
  721. X         * (at least one when not at the top level). Other stuff can be
  722. X         * accepted only after we have seen at least one word (two words
  723. X         * when not at the top level). See also the above comment on
  724. X         * structs and unions.
  725. X         */
  726. X
  727. X        if (t->tokno == TOK_LIST && LIST_BEGINS_WITH_STAR(t)) {
  728. X        if (t = func_ptr_dcl_flush(t)) {
  729. X            return (t);            /* reject token */
  730. X        } else {
  731. X            got_word = 1;        /* for = and [ and , and ; */
  732. X        }
  733. X        } else if (got_word == 0) {
  734. X        return (t);            /* reject token */
  735. X        } else {
  736. X        switch (t->tokno) {
  737. X        case TOK_LIST:            /* function type */
  738. X            if (t = function_dcl_flush(t))
  739. X            return (t);        /* reject token */
  740. X            break;
  741. X        case '[':            /* dimension, does not nest */
  742. X            pair_flush(t, '[', ']');
  743. X            break;
  744. X        case '=':            /* initializer follows */
  745. X            tok_flush(t);
  746. X            initializer();        /* rewrite casts */
  747. X            break;
  748. X        case '{':            /* struct, union, may nest */
  749. X            block_flush(t);        /* use code for stmt blocks */
  750. X            break;
  751. X        case ',':            /* separator: keep trying */
  752. X            got_word = 0;
  753. X            tok_flush(t);
  754. X            break;
  755. X        case ';':            /* terminator: succeed */
  756. X            tok_flush(t);
  757. X            return (0);
  758. X        default:            /* reject token */
  759. X            return (t);
  760. X        }
  761. X        }
  762. X    }
  763. X    }
  764. X    return (0);                    /* hit EOF */
  765. X}
  766. END_OF_unproto.c
  767. if test 19406 -ne `wc -c <unproto.c`; then
  768.     echo shar: \"unproto.c\" unpacked with wrong size!
  769. fi
  770. # end of overwriting check
  771. fi
  772. echo shar: End of archive 2 \(of 2\).
  773. cp /dev/null ark2isdone
  774. MISSING=""
  775. for I in 1 2 ; do
  776.     if test ! -f ark${I}isdone ; then
  777.     MISSING="${MISSING} ${I}"
  778.     fi
  779. done
  780. if test "${MISSING}" = "" ; then
  781.     echo You have unpacked both archives.
  782.     rm -f ark[1-9]isdone
  783. else
  784.     echo You still need to unpack the following archives:
  785.     echo "        " ${MISSING}
  786. fi
  787. ##  End of shell archive.
  788. exit 0
  789.  
  790. exit 0 # Just in case...
  791. -- 
  792. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  793. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  794. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  795. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  796.